import 'reflect-metadata';
import Router, { IRouterContext } from 'koa-router';
import { Context } from 'koa'
import requireContext from 'require-context';
import { allDone } from '../utils/myPromiseUtils';
import { routerResponseHandler } from '../middlewares/responseHandler'
import logger from '../utils/logger';
import Log from '../entity/db1/log';
import LogService from '../service/logService';
import util from 'util';
import swaggerRouter from './swaggerHandler';
import path from 'path';
const logService = new LogService();
const controllerDir = process.env.NODE_ENV === 'dev' ? '../../dist/controller' : path.resolve(__dirname, '../controller');
const controllers = requireContext(controllerDir, true, /(.+)(Controller\.js){1}$/);
const set = new Set();
const router: Router = new Router();
/**
 * 添加控制器路由
 * @param Controller
 */
const addRouter = (Controller) => {
  const controller = new Controller();
  const clsRouter = Reflect.getMetadata('Controller', Controller);
  logger.apiTitle(` ${clsRouter.name} :`);
  const methods = Reflect.ownKeys(Controller.prototype);
  methods.forEach((method) => {
    const methodRouter = Reflect.getMetadata('Router', controller, String(method));
    if (methodRouter) {
      const key = `${clsRouter.path}${methodRouter.path}`;
      if (set.has(key)) {
        logger.error(`【${key}】已经存在，请检查!`);
        return;
      }

      set.add(key);
      const path = `${methodRouter.name} ${methodRouter.method} : ${clsRouter.path}${methodRouter.path}`;
      logger.api(path);
      router[methodRouter.method.toLowerCase()](
        `${clsRouter.path}${methodRouter.path}`,
        async (ctx: Context) => {
          const methodName = `${clsRouter.name} -> ${Controller.name}::${String(method)}`;
          let data = null;
          let log: Log = null;
          let error = null;
          try {
            logger.request(`请求 ${methodName} ...`);
            data = await controller[method](ctx);
            logger.request(`执行 ${methodName} 业务成功! 返回: ${JSON.stringify(data)}`);
            routerResponseHandler(ctx, data)
          } catch (ex) {
            error = util.inspect(ex, { depth: null, compact: true });
            logger.request(`执行 ${methodName} 业务失败! 原因: ${ex}`);
            routerResponseHandler(ctx, ex)
          }
          log = new Log({
            requestName: `${clsRouter.name}:${methodRouter.name}`,
            requestType: ctx.request.method,
            requestPath: ctx.request.path,
            requestHeaders: util.inspect(ctx.request.headers, { depth: null, compact: true }),
            responseHeaders: util.inspect(ctx.response.headers, { depth: null, compact: true }),
            requestData: util.inspect(ctx.request.method === 'post' ? ctx.request.body : ctx.query || ctx.params, { depth: null, compact: true }),
            responseData: util.inspect(data, { depth: null, compact: true }),
            requestHost: ctx.headers.origin || ctx.request.origin || ctx.host,
            requestIp: ctx.request.ip,
            error
          });
          await logService.insertLog(log);
        },
      );
    }
  });

};

const initRouter = async () => {
  logger.info('=========== init routers begin ===========');
  const allController = await allDone(controllers.keys().map(controllerName => import(`../controller/${controllerName}`)));
  allController.forEach((controller) => {
    addRouter(controller.default);
  });
  router.use(swaggerRouter.routes()).use(swaggerRouter.allowedMethods());
  logger.info('============ init routers success ============');
};

export { router };
export default initRouter;
